package main

import (
	"context"
	"fmt"
	"log"
	"net"
	"os"
	"os/signal"
	"syscall"
	"time"

	notificationv1 "github.com/devops-smartbot/devops-smartbot/proto/gen/go/notification/v1"
	"github.com/devops-smartbot/devops-smartbot/services/notification-service/internal/channels"
	grpcserver "github.com/devops-smartbot/devops-smartbot/services/notification-service/internal/grpc"
	"github.com/devops-smartbot/devops-smartbot/services/notification-service/internal/repository"
	"github.com/devops-smartbot/devops-smartbot/services/notification-service/internal/service"
	"github.com/devops-smartbot/devops-smartbot/shared/database"
	"google.golang.org/grpc"
	"google.golang.org/grpc/health"
	"google.golang.org/grpc/health/grpc_health_v1"
	"google.golang.org/grpc/reflection"
)

func main() {
	// Get configuration from environment
	port := getEnv("GRPC_PORT", "50053")
	mongoURI := getEnv("MONGO_URI", "mongodb://localhost:27017")
	dbName := getEnv("MONGO_DB_NAME", "devops_smartbot")

	// Email configuration
	emailConfig := channels.EmailConfig{
		SMTPHost:     getEnv("SMTP_HOST", "smtp.gmail.com"),
		SMTPPort:     getEnv("SMTP_PORT", "587"),
		SMTPUsername: getEnv("SMTP_USERNAME", ""),
		SMTPPassword: getEnv("SMTP_PASSWORD", ""),
		FromAddress:  getEnv("SMTP_FROM_ADDRESS", "noreply@devops-smartbot.com"),
		FromName:     getEnv("SMTP_FROM_NAME", "DevOps SmartBot"),
	}

	// Slack configuration
	slackConfig := channels.SlackConfig{
		WebhookURL: getEnv("SLACK_WEBHOOK_URL", ""),
		BotToken:   getEnv("SLACK_BOT_TOKEN", ""),
	}

	// Connect to MongoDB
	log.Println("Connecting to MongoDB...")
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	db, err := database.Connect(ctx, mongoURI, dbName)
	if err != nil {
		log.Fatalf("Failed to connect to MongoDB: %v", err)
	}
	log.Println("Connected to MongoDB")

	// Initialize repository and service
	notificationRepo := repository.NewNotificationRepository(db)
	notificationService := service.NewNotificationService(notificationRepo, emailConfig, slackConfig)

	// Create gRPC server
	grpcServer := grpc.NewServer()

	// Register notification service
	server := grpcserver.NewServer(notificationService)
	notificationv1.RegisterNotificationServiceServer(grpcServer, server)

	// Register health check
	healthServer := health.NewServer()
	grpc_health_v1.RegisterHealthServer(grpcServer, healthServer)
	healthServer.SetServingStatus("", grpc_health_v1.HealthCheckResponse_SERVING)

	// Register reflection for grpcurl
	reflection.Register(grpcServer)

	// Start gRPC server
	listener, err := net.Listen("tcp", fmt.Sprintf(":%s", port))
	if err != nil {
		log.Fatalf("Failed to listen: %v", err)
	}

	log.Printf("Notification Service listening on port %s", port)

	// Start retry worker in background
	go startRetryWorker(notificationService)

	// Handle graceful shutdown
	go func() {
		if err := grpcServer.Serve(listener); err != nil {
			log.Fatalf("Failed to serve: %v", err)
		}
	}()

	// Wait for interrupt signal
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit

	log.Println("Shutting down notification service...")
	grpcServer.GracefulStop()
	log.Println("Notification service stopped")
}

// startRetryWorker retries failed notifications periodically
func startRetryWorker(notificationService *service.NotificationService) {
	ticker := time.NewTicker(5 * time.Minute)
	defer ticker.Stop()

	for range ticker.C {
		ctx := context.Background()
		if err := notificationService.RetryFailedNotifications(ctx); err != nil {
			log.Printf("Failed to retry notifications: %v", err)
		}
	}
}

func getEnv(key, defaultValue string) string {
	if value := os.Getenv(key); value != "" {
		return value
	}
	return defaultValue
}
